package main

import (
	"context"
	userserver "hertz_demo/kitex/user/kitex_gen/userserver"
	"hertz_demo/orm"
	"hertz_demo/orm/cache"
	"hertz_demo/orm/db"

	"github.com/redis/go-redis/v9"
	"gorm.io/gorm"
)

// UserServiceImpl implements the last service interface defined in the IDL.
type UserServiceImpl struct{}

// GetUserById implements the UserServiceImpl interface.
func (s *UserServiceImpl) GetUserById(ctx context.Context, req *userserver.GetUserByIdRequest) (resp *userserver.GetUserByIdResponse, err error) {
	// TODO: Your code here...
	resp = new(userserver.GetUserByIdResponse)
	user, err := cache.GetUserById(req.UserId)
	if err == redis.Nil {
		dbUser := new(db.User)
		db.DB.Model(&db.User{}).Find(dbUser, req.UserId)
		err = cache.SetUser(dbUser)
		if err != nil {
			panic(err)
		}
		if dbUser.ID != 0 {
			user.ID = int64(dbUser.ID)
			user.Name = dbUser.Name
			user.FollowCount = dbUser.FollowCount
			user.FollowerCount = dbUser.FollowerCount
			user.IsFollow = false
		}
	} else if err != nil {
		panic(err)
	}
	u := userserver.User(user)
	resp.User = &u
	return
}

// CreateUser implements the UserServiceImpl interface.
func (s *UserServiceImpl) CreateUser(ctx context.Context, req *userserver.CreateUserRequest) (resp *userserver.CreateUserResponse, err error) {
	// TODO: Your code here...
	resp = new(userserver.CreateUserResponse)
	newUser := db.User{
		Name:          req.Username,
		Password:      req.Password,
		FollowCount:   0,
		FollowerCount: 0,
	}
	err = db.DB.Transaction(func(tx *gorm.DB) error {
		var nameCnt int64 = 0
		if err := tx.Table("users").Where("name = ?", req.Username).Count(&nameCnt).Error; err != nil {
			return err
		}
		if nameCnt != 0 {
			return gorm.ErrInvalidData
		}
		if err := tx.Create(&newUser).Error; err != nil {
			return gorm.ErrInvalidData
		}
		return nil
	})
	if err == nil {
		token := orm.GenerateToken(newUser.Name)
		orm.SetToken(int64(newUser.ID), token)
	}

	resp.UserId = newUser.ID
	return
}

// GetUserByName implements the UserServiceImpl interface.
func (s *UserServiceImpl) GetUserByName(ctx context.Context, req *userserver.GetUserByNameRequest) (resp *userserver.GetUserByNameResponse, err error) {
	resp = new(userserver.GetUserByNameResponse)
	user, err := cache.GetUserByName(req.Username)
	if err == redis.Nil {
		dbUser := new(db.User)
		db.DB.Model(&db.User{}).Find(dbUser, "name = ?", req.Username)
		err = cache.SetUser(dbUser)
		if err != nil {
			panic(err)
		}
		if dbUser.ID != 0 {
			user.ID = int64(dbUser.ID)
			user.Name = dbUser.Name
			user.FollowCount = dbUser.FollowCount
			user.FollowerCount = dbUser.FollowerCount
			user.IsFollow = false
		}
	} else if err != nil {
		panic(err)
	}

	u := userserver.User{
		ID:            user.ID,
		Name:          user.Name,
		FollowCount:   user.FollowCount,
		FollowerCount: user.FollowerCount,
		IsFollow:      user.IsFollow,
	}
	resp.User = &u
	return
}

// LoginUser implements the UserServiceImpl interface.
func (s *UserServiceImpl) LoginUser(ctx context.Context, req *userserver.LoginUserRequest) (resp *userserver.LoginUserResponse, err error) {
	// TODO: Your code here...
	resp = new(userserver.LoginUserResponse)
	dbUser := new(db.User)
	db.DB.Model(&db.User{}).Find(dbUser, "name = ?", req.Username)
	if dbUser.Password != req.Password {
		err = gorm.ErrInvalidValue
	} else {
		resp.Token = orm.GenerateToken(req.Username)
		orm.SetToken(dbUser.ID, resp.Token)
		resp.UserId = dbUser.ID
		err = nil
	}
	return
}
